/* ****************************************************************************
 *
 * Copyright (c) Microsoft Corporation. 
 *
 * This source code is subject to terms and conditions of the Microsoft Public License. A 
 * copy of the license can be found in the License.html file at the root of this distribution. If 
 * you cannot locate the  Microsoft Public License, please send an email to 
 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
 * by the terms of the Microsoft Public License.
 *
 * You must not remove this notice, or any other, from this software.
 *
 * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
 * PARTICULAR PURPOSE.
 * ***************************************************************************/


#include "StdAfx.h"
#include "gdipisapi.h"

int CGDIpISAPI::GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
	using namespace Gdiplus;
	UINT  num = 0;          // number of image encoders
	UINT  size = 0;         // size of the image encoder array in bytes

	ImageCodecInfo* pImageCodecInfo = NULL;

	GetImageEncodersSize(&num, &size);
	if(size == 0)
		return -1;  // Failure

	pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
	if(pImageCodecInfo == NULL)
		return -1;  // Failure

	GetImageEncoders(num, size, pImageCodecInfo);

	for(UINT j = 0; j < num; ++j)
	{
		if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 )
		{
			*pClsid = pImageCodecInfo[j].Clsid;
			free(pImageCodecInfo);
			return j;  // Success
		}    
	}

	free(pImageCodecInfo);
	return -1;  // Failure
}

void CGDIpISAPI::WriteContext(LPCTSTR pszFormat,...)
{
	static TCHAR szBuffer[1024];
	
	if (!m_pCtxt)
		return;

	va_list arg_ptr;
	va_start(arg_ptr, pszFormat);
	vsprintf(szBuffer,pszFormat, arg_ptr);
	va_end(arg_ptr);

	*m_pCtxt<<szBuffer;
}

void CGDIpISAPI::DumpError(LPCTSTR pszFormat, ...)
{
	static TCHAR szBuffer[2048];

	if (!m_pCtxt)
		return;

	va_list arg_ptr;
	va_start(arg_ptr, pszFormat);
	vsprintf(szBuffer,pszFormat, arg_ptr);
	va_end(arg_ptr);

	CString str("<p>A error message has occured:</p>\r\n<p><b>");
	str+=szBuffer;
	str+="</b></p>\r\n";

	DWORD dwSize=(DWORD)str.GetLength();

	m_pServer->StartContent(m_pCtxt);
	*m_pCtxt<<str;
	m_pServer->EndContent(m_pCtxt);
}

void CGDIpISAPI::WriteImage()
{
	using namespace Gdiplus;
	USES_CONVERSION;

	CString str;
	CString strHeader;
	SIZE_T size;
	EncoderParameters encoderParameters;
 
	if (!m_pCtxt)
		return;
	if (!m_pServer)
		return;
	if (!m_pImage)
		return;

	algotools::CMemStream memStream;
	if (!memStream.IsValid())
	{
		ISAPIASSERT(FALSE);
		return;
	}

	CLSID imgClsid;
	if (GetEncoderClsid(A2BSTR(GetImageTypeString()), &imgClsid) == -1)
	{
		ISAPIASSERT(FALSE);
		return;
	}

	GetEncoderParameters(encoderParameters);
	// Save to IStream...
	m_pImage->Save(memStream.ToStream(), &imgClsid, &encoderParameters);

	if (m_pImage->GetLastStatus() != Gdiplus::Ok)
	{
		ISAPIASSERT(FALSE);
		return;
	}

	// getting size of hGlobal
	size = memStream.Size();
	// formulate a proper header
	m_pCtxt->m_bSendHeaders=FALSE;
	strHeader.Format(_T("HTTP/1.0 200 OK\r\n%s\r\nContent-length: %d\r\n\r\n"), GetImageTypeString(),size);
	m_pServer->AddHeader(m_pCtxt, strHeader);
	ISAPIVERIFY( m_pCtxt->m_pECB->WriteClient(
		m_pCtxt->m_pECB->ConnID, memStream.LockToLPVOID(), &size, 0) );
}

LPCTSTR CGDIpISAPI::GetImageTypeString() const
{
	switch(m_eImageType)
	{
	case ImagePNG:
		return "image/png";
	case ImageJPEG:
		return "image/jpeg";
	case ImageBMP:
		return "image/bmp";
	default:
		return "text/plain";
	}
}

void CGDIpISAPI::WriteInfo()
{
	using namespace Gdiplus;
	USES_CONVERSION;

	CString str;
	CString strHeader;
	EncoderParameters encoderParameters;

	if (!m_pCtxt)
		return;
	if (!m_pServer)
		return;
	if (!m_pImage)
		return;

	algotools::CMemStream memStream;
	if (!memStream.IsValid())
	{
		ISAPIASSERT(FALSE);
		return;
	}

	CLSID imgClsid;
	if (GetEncoderClsid(A2BSTR(GetImageTypeString()), &imgClsid) == -1)
	{
		ISAPIASSERT(FALSE);
		return;
	}

	GetEncoderParameters(encoderParameters);
	// Save to IStream...
	m_pImage->Save(memStream.ToStream(), &imgClsid, &encoderParameters);

	if (m_pImage->GetLastStatus() != Gdiplus::Ok)
	{
		ISAPIASSERT(FALSE);
		return;
	}

		
	m_pServer->StartContent(m_pCtxt);
	WriteContext("<table>\r\n");
	WriteContext("<tr><td>Image Type</td><td>%s</td></tr>\r\n",GetImageTypeString());
	WriteContext("<tr><td>Size</td><td>%dx%d</td></tr>\r\n", m_pImage->GetWidth(), m_pImage->GetHeight());
	WriteContext("<tr><td>Size (Bytes)</td><td>%d</td></tr>\r\n", memStream.Size());
	WriteContext("</table>\r\n");
	m_pServer->EndContent(m_pCtxt);
}


void CGDIpISAPI::GetEncoderParameters(Gdiplus::EncoderParameters& encode)
{
	switch( m_eImageType )
	{
	case ImageJPEG:
		if (m_eJPEGTransform == JPEGTransformNone)
		{
			encode.Count = 1;
		}
		else
		{
			encode.Count = 2;
			encode.Parameter[1].Guid = Gdiplus::EncoderTransformation;
			encode.Parameter[1].Type = Gdiplus::EncoderParameterValueTypeLong;
			encode.Parameter[1].NumberOfValues = 1;
			encode.Parameter[1].Value = &m_eJPEGTransform;
		}

		encode.Parameter[0].Guid = Gdiplus::EncoderQuality;
		encode.Parameter[0].Type = Gdiplus::EncoderParameterValueTypeLong;
		encode.Parameter[0].NumberOfValues = 1;
		encode.Parameter[0].Value = &m_lJPEGQuality;
		break;
	default:
		encode.Count=0;
	}
};
